package snapex.invoice.controller;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import snapex.core.model.Invoice;
import snapex.core.model.InvoiceImage;
import snapex.core.model.Result;
import snapex.invoice.service.IInvoiceService;

@Slf4j
@RestController
public class InvoiceController {

	@Autowired
	IInvoiceService invoiceService;
	
	@ApiOperation(value="add invoice")	
	@PostMapping("/invoice/add")
    public ResponseEntity<Result> addInvoice(@RequestBody Invoice invoice) {
			
		return ResponseEntity.ok(Result.success().data(invoiceService.saveInvoice(invoice)));
	}	
	
	@ApiOperation(value="Get invoice")
	@ApiImplicitParam(name = "invoiceId", value = "invoice id", required = true, dataType = "String")
	@GetMapping(value = "/invoice/{invoiceId}", produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResponseEntity<Result> getInvoice(@PathVariable String invoiceId) {
		
		return ResponseEntity.ok(Result.success().data(invoiceService.getInvoice(invoiceId)));			
	}

	
	@ApiOperation(value="Upload invoice image")
	@PostMapping(value = "/invoice/{invoiceId}/upload", produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResponseEntity<Result> uploadImage(@PathVariable String invoiceId, @RequestParam("invoice") MultipartFile invoice) throws IOException {
		
		if(invoice.isEmpty()) {
			ResponseEntity.ok(Result.failure().id(invoiceId));	
		}
        
		invoiceService.saveInvoiceImage(invoiceId, invoice.getBytes(),invoice.getContentType().substring("image/".length()));
		
		return ResponseEntity.ok(Result.success().id(invoiceId));			
	}
	
	@Value("${snapex.accessKeyValidPeriodSecond}")
	long accessKeyValidPeriodSecond;
	
	@ApiOperation(value = "Get invoice image")
	@GetMapping(value = "/invoice/{invoiceId}/image")
	public ResponseEntity<Object> getImage(@PathVariable String invoiceId, @RequestParam String accessKey) throws Exception {
		
		long period = System.currentTimeMillis() - Long.parseLong(accessKey);		
		
		log.debug("*****Expired period:{}  accessKeyValidPeriodSecond:{}", period/1000L,  accessKeyValidPeriodSecond);	
		
		if(period < 0 || period/1000L > accessKeyValidPeriodSecond) {
			log.debug("*****Invalid accessKey:{}", accessKey);	
			return ResponseEntity.status(HttpStatus.OK).contentType(MediaType.APPLICATION_PROBLEM_JSON_UTF8).body(Result.failure().msg("Invalid accessKey"));
		}
		
		InvoiceImage image = invoiceService.getInvoiceImage(invoiceId);
		
		return ResponseEntity.status(HttpStatus.OK).contentType(new MediaType("image",image.getMime())).body(image.getImage());
	}

	@ApiOperation(value = "Download a list of invoice images")
	@PostMapping(value = "/invoice/image/download")
	public ResponseEntity<byte[]> getImages(@RequestBody Map<String/*invoiceId*/,String/*tag*/> invoiceIdTagMap) throws Exception {
			
		log.debug("*****invoice ids={}, tags={}",invoiceIdTagMap.keySet(), invoiceIdTagMap.values());
		
		ByteArrayOutputStream baos = new ByteArrayOutputStream();			
		ZipOutputStream zipOs = new ZipOutputStream(baos);
		
		List<InvoiceImage> images = invoiceService.getInvoiceImages(Arrays.asList(invoiceIdTagMap.keySet().toArray(new String[]{})));					
		for(InvoiceImage image : images) {
			zipOs.putNextEntry(new ZipEntry(invoiceIdTagMap.get(image.getInvoiceId()) +"-"+ image.getInvoiceId() +"."+ image.getMime()));
			zipOs.write(image.getImage());
			zipOs.closeEntry();	
		}
		zipOs.close();
			
		String filename = new StringBuffer("snapex-invoice-").append(DateFormatUtils.format(System.currentTimeMillis(), "yyyy-MM-dd_HH_mm_ss")).append(".zip").toString();
		
		return ResponseEntity.ok()
				.contentType(MediaType.APPLICATION_OCTET_STREAM)
				.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename="+filename)
				.body(baos.toByteArray());		
	}	
}
